﻿using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Fibre.Threading.Tests
{
    [TestClass]
    public class ErrorHandlingTests
    {
        private readonly AsyncWork _asyncWork;
        private readonly Exception _ex;

        public ErrorHandlingTests()
        {
            _ex = new Exception();
            _asyncWork = new AsyncWork();
        }

        [TestMethod]
        public void ActionCapturesErrors()
        {
            Exception capturedException = null;

            _asyncWork
                .AddWork(() => { throw _ex; })
                .WhenComplete(c => capturedException = c.Error)
                .PerformWork()
                .WaitForCompletion();

            Assert.AreEqual(_ex, capturedException);
        }

        [TestMethod]
        public void FuncCapturesErrors()
        {
            Exception capturedException = null;

            _asyncWork
                .AddWork((Func<string>)(() => { throw _ex; }))
                .WhenComplete(c => capturedException = c.Error)
                .PerformWork()
                .WaitForCompletion();

            Assert.AreEqual(_ex, capturedException);
        }

        [TestMethod]
        public void AsyncPatternCapturesErrors()
        {
            Exception capturedException = null;
            Action test = () => { throw _ex; };

            _asyncWork
                .AddWork(test.BeginInvoke, test.EndInvoke)
                .WhenComplete(c => capturedException = c.Error)
                .PerformWork()
                .WaitForCompletion();

            Assert.AreEqual(_ex, capturedException);
        }

        [TestMethod]
        public void SecondChainActionCapturesErrors()
        {
            Exception capturedException = null;

            _asyncWork
                .AddWork(() => { })
                .WhenComplete(c => c.AddWork(()=> { throw _ex; }).WhenComplete(r=> capturedException = r.Error))
                .PerformWork()
                .WaitForCompletion();

            Assert.AreEqual(_ex, capturedException);
        }

        [TestMethod]
        public void SecondChainFuncCapturesErrors()
        {
            Exception capturedException = null;

            _asyncWork
                .AddWork(() => "")
                .WhenComplete(c => c.AddWork(() => { throw _ex; }).WhenComplete(r => capturedException = r.Error))
                .PerformWork()
                .WaitForCompletion();

            Assert.AreEqual(_ex, capturedException);
        }

        [TestMethod]
        public void SecondChainAsyncPatternCapturesErrors()
        {
            Exception capturedException = null;
            Action test = () => { throw _ex; };
            Action exTest = () => { throw _ex; };

            _asyncWork
                .AddWork(test.BeginInvoke, test.EndInvoke)
                .WhenComplete(c => c
                    .AddWork(exTest.BeginInvoke, exTest.EndInvoke)
                    .WhenComplete(r => capturedException = r.Error))
                .PerformWork()
                .WaitForCompletion();

            Assert.AreEqual(_ex, capturedException);
        }
    }
}
